# -*- coding: utf-8 -*-
'''
Copyright(C) 2013 "Kevin Xu <ssonxu@gmail.com>"

This file is part of acqu-center.

acqu-center is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

acqu-center is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with acqu-center.  If not, see <http://www.gnu.org/licenses/>.
'''
import logging
from Predef import Predef as PRE
from google.appengine.ext import ndb
from parser import parser as ROCK

class Value(ndb.Model):
    date = ndb.DateTimeProperty(required=True, auto_now_add=True)
    val = ndb.StringProperty(required=True)

class Stuff(ndb.Model):
    itemID = ndb.StringProperty(default='')
    pattern = ndb.StringProperty(required=True, indexed=False)

    val = ndb.StructuredProperty(Value, repeated=True, indexed=False) 

    message = ndb.StringProperty(required=True, indexed=False)
    expression = ndb.StringProperty(required=True, indexed=False)
    p1 = ndb.StringProperty(default=u'0', indexed=False)
    p2 = ndb.StringProperty(default=u'0', indexed=False)

    ref = ndb.StringProperty(default=u'0', indexed=False)

    ############
    # process
    ############
    def keepref(self):
        self.ref = self.val[0].val
        #logging.info(self.ref)

    def ID(self):
        if len(self.itemID)==0:
            self.itemID = PRE.getTimeStamp()
        return self.itemID

    def setVal(self,v):
        if len(self.val)>PRE.MAX_DATA_ROWS:
            self.val.pop()
        else:
            self.val.insert(0,Value(val=v))

    def isMatched(self):
        lam = u"lambda val,ref,p1,p2:%s" % self.expression
        return eval(lam)(self.val[0].val, self.ref, self.p1, self.p2)

    @classmethod
    def getStuff(cls, ID):
        query = cls.query(cls.itemID == ID)
        return query.get()

class Box(ndb.Model):
    ############
    # Initialize
    ############
    label = ndb.StringProperty(required=True)
    url = ndb.StringProperty(default=PRE.url_)
    description = ndb.StringProperty(indexed=False,default='')
    catagory = ndb.StringProperty(default='')
    stuffs = ndb.LocalStructuredProperty(Stuff, repeated=True, indexed=False)
    isRunning = ndb.BooleanProperty(default=False)

    ############
    # process
    ############
    def ID(self):
        return self.key.id()

    def lauchIt(self):
        self.isRunning=True
        self.put()

    def drawbackIt(self):
        self.isRunning=False
        self.put()


    def hasUpdate(self):
        for k in self.stuffs:
            if k.isMatched():
                return True
        return False

    def report(self,isReportAll=False, isSkipMatch=False, isHTML=False):
        Content=[]
        if isSkipMatch or self.hasUpdate():
            for k in self.stuffs:
                if isSkipMatch or isReportAll or k.isMatched():
                    c = k.message.format(k.val[0].val, k.ref)
                    Content.append(u"<p>{}</p>".format(c)
                             if isHTML else c)

                # flush the reference if has reported 
                #if k.isMatched():
                #    k.keepref()

        if len(Content)>0:
            # add desciption and header
            if isHTML:
                return u'<p>{}-{}</p>-----------------------<p>{}</p>-----------------------<p>Source: {}</p>-----------------------'.format(
                    self.ID(),self.label,u'\n'.join(Content), self.url)
            else:
                return u'{}-{}\n-----------------------\n{}\n-----------------------\nSource: {}\n-----------------------'.format(
                    self.ID(),self.label,u'\n'.join(Content), self.url)

        return ''

    def exportData(self):
        return [ x.val for x in self.stuffs ]

    def export(self):
        ex = self.to_dict(exclude=['stuffs'])
        ex['stuffs']=[ x.to_dict(exclude=['val']) for x in self.stuffs ]
        return ex

    ############
    # class
    ############
    @classmethod
    def flush(cls):
        ll=cls.listBoxes(Running=True)
        for x in ll:
            dirty=False
            for k in x.stuffs:
                if k.isMatched():
                    k.keepref()
                    dirty=True
            if dirty:
                x.put()
        

    @classmethod
    def getMenu(cls, Running=False):
        res=[]
        ll=cls.listBoxes(Running=True)
        for x in ll:
            res.append(u"{}. {} - {}".format(x.ID(), x.label, x.description))

        return u'\n\n'.join(res)

    @classmethod
    def listBoxes(cls, Running=False, Limit=None, Offset=0):
        query = cls.query(cls.isRunning == Running).order(cls.label)
        return query.fetch(limit=Limit, offset=Offset)

    @classmethod
    def getBox(cls, label):
        query = cls.query(cls.label == label)
        return query.get()

    @staticmethod
    def getBoxByID(ID):
        return ndb.Key(Box, ID).get()

    @classmethod
    def delBoxByID(cls, ID):
        b = Box.getBoxByID(ID)
        if b is not None:
            return b.key.delete()
        return None
        
    @classmethod
    def rockMe(cls):
        for x in cls.listBoxes(Running=True):
            #try:
            #    x.flush()
            #except IndexError, e:
            #    logging.error(e)
            ROCK(x).run()
            x.put()

    ############
    # export & import
    ############
    @classmethod
    def exportDict(cls, label=None):
        if label is None:
            return [p.export() for p in cls.query().fetch()]
        else:
            return Box.getBox(label).export()

    @classmethod
    def importDict(cls, dic):
        for d in dic:
            b=Box( label=d['label'],isRunning=d['isRunning'],description=d['description'],url=d['url'],
                    catagory=d['catagory'] )
            b.stuffs=[]
            for s in d['stuffs']: 
                if 'itemID' in  s.keys() and len(s['itemID'])>0:
                    st=Stuff( itemID= s['itemID'], pattern=s['pattern'], message=s['message'], expression=s['expression'], p1=s['p1'], p2=s['p2'] )
                else:
                    st=Stuff( pattern=s['pattern'] , message=s['message'], expression=s['expression'], p1=s['p1'], p2=s['p2'] )
                    st.ID()
                b.stuffs.append(st)
            b.put()
